using System.Text;
using MultiAgentsClient.ChatDataStructures;
using MultiAgentsShared;
using OpenAI.ObjectModels.RequestModels;

namespace MultiAgentsClient.Service;

public class MessageCollectionHelper : TimedDisposableBase
{
    public MessageCollectionHelper() : base(120000)
    {
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
        }

        base.Dispose(disposing);
    }

    private readonly SortedDictionary<int, (string? messageSlice, List<ToolCall>? toolCalls)> sliceIdAndContents = [];
    private readonly StringBuilder sb = new();
    private int lastIndex = -1;

    private List<int>? historyMessagesIdList;
    private List<ToolCall>? toolCalls;
    private int messageId = 0;
    private int senderId = 0;
    private string authorName = "";
    private readonly SemaphoreSlim semaphore = new(1, 1);

    public async Task<ChatMessageData?> UpdateRespondedMsgFromStream(int senderId, int messageId, int sliceIndex, string author, string? messageSlice, DateTime dateTime, List<int>? historyMessagesIdList, List<ToolCall>? toolCalls)
    {
        if (this.messageId == 0)
        {
            this.messageId = messageId;
            this.senderId = senderId;
            authorName = ChatStringExtension.NameAsSystemReadable(author);
        }

        if (historyMessagesIdList != null)
        {
            this.historyMessagesIdList = historyMessagesIdList;
        }

        if (toolCalls != null)
        {
            this.toolCalls = toolCalls;
        }
        
        await semaphore.WaitAsync();

        try
        {
            sliceIdAndContents.Add(sliceIndex, (messageSlice, toolCalls));

            ChatMessageData? chatMessageData = CollectMessageSlices(dateTime);

            return chatMessageData;
        }
        catch(Exception)
        {
            throw Debug.ShouldNotHappen();
        }
        finally
        {
            semaphore.Release();
        }
    }

    private ChatMessageData? CollectMessageSlices(DateTime dateTime)
    {
        int preLastIndex = lastIndex;
        SortedDictionary<int, (string? messageSlice, List<ToolCall>? toolCalls)> deepCopySliceIdAndContents = new(sliceIdAndContents);

        for (int i = lastIndex + 1; i < deepCopySliceIdAndContents.Count; i++)
        {
            if (deepCopySliceIdAndContents.ElementAt(i).Key != i || deepCopySliceIdAndContents.ElementAt(i).Value.messageSlice == null)
            {
                break;
            }

            sb.Append(deepCopySliceIdAndContents.ElementAt(i).Value.messageSlice);
            lastIndex++;
        }

        bool isFinished = sliceIdAndContents.Last().Key == sliceIdAndContents.Count - 1 && sliceIdAndContents.Last().Value.messageSlice == null && sliceIdAndContents.Last().Value.toolCalls == null;
        if (preLastIndex == lastIndex && isFinished == false)
        {
            return null;
        }
        else
        {
            ChatMessageData chatCache = ChatMessageData.FromAssistant(messageId, senderId, sb.ToString(), historyMessagesIdList, 0, authorName, isFinished, dateTime, toolCalls);

            return chatCache;
        }
    }
}
